package com.gome.ocean.controller.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gome.framework.util.ObjectFactoryUtil;
import com.gome.ocean.common.enums.authority.UrlMethodType;
import com.gome.ocean.common.utils.ResponsePage;
import com.gome.ocean.dao.model.authority.User;
import com.gome.ocean.dao.model.authority.UserOptLogBO;
import com.gome.ocean.dao.model.reqres.AccessRequest;
import com.gome.ocean.dao.model.reqres.AccessResponse;
import com.gome.ocean.service.authority.AuthorityManager;
import com.gome.ocean.service.authority.IUserOptLogService;
import com.gome.ocean.service.base.BaseController;
import com.google.common.collect.Maps;

/**
 * Created by liuqingxia on 2016/2/22.
 */
public class AuthorityFilter extends BaseController implements Filter {

    private static final Logger LOG = LoggerFactory.getLogger(AuthorityFilter.class);

    private AuthorityManager    authorityManager;
    private String              contextPath;
    private IUserOptLogService  userOptLogService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        if (null == authorityManager) {
            authorityManager = (AuthorityManager) ObjectFactoryUtil.getObject("@authorityManager");
        }
        contextPath = filterConfig.getServletContext().getContextPath();
    }

    public AuthorityManager getAuthorityManager() {
        return authorityManager;
    }

    public void setAuthorityManager(AuthorityManager authorityManager) {
        this.authorityManager = authorityManager;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException,
                                                                                          ServletException {
        userOptLogService = (IUserOptLogService) ObjectFactoryUtil.getObject("@userOptLogService");
        AccessResponse accessResponse = authorityManager.permitAccess(assemblyAccessReq(req));
        if (accessResponse.isPermit()) {
            this.userOptReq(req, userOptLogService);
            filterChain.doFilter(req, res);
            return;
        }
        if (!accessResponse.isHadLogin()) {
            String requestHead = ((HttpServletRequest) req).getHeader("x-requested-with");
            if (StringUtils.isNotEmpty(requestHead) && requestHead.equalsIgnoreCase("XMLHttpRequest")) {
                responseJson((HttpServletResponse) res, accessResponse);
                return;
            } else {
                req.getRequestDispatcher("/").forward(req, res);
                return;
            }
        }
        if (getMethodType(req).equals(UrlMethodType.POST)) {
            responseJson((HttpServletResponse) res, new ResponsePage().setErrorMsg(accessResponse.getMessage()));
            return;
        }
        req.setAttribute("message", accessResponse.getMessage());
        req.getRequestDispatcher("/message").forward(req, res);
    }

    private void userOptReq(ServletRequest req, IUserOptLogService iUserOptLogService) {
        Map<String, Object> mapParam = Maps.newHashMap();
        Enumeration<String> enumer = req.getParameterNames();
        while (enumer.hasMoreElements()) {
            String key = (String) enumer.nextElement();
            String[] values = req.getParameterValues(key);
            if (values.length == 1) {
                String value = values[0];
                if (value.length() != 0) {
                    mapParam.put(key, value);
                }
            }
        }
        if (mapParam != null && mapParam.size() > 0) {
            UserOptLogBO logBO = new UserOptLogBO();
            Map<String, Object> map = super.getLocalHostIpAndNameAndSysInfo();
            AccessRequest request = this.assemblyAccessReq(req);
            logBO.setFunctionUrl(request.getUrl());
            logBO.setOptTime(new Date());
            User user = (User) request.getSession().getAttribute("currentLoginUser");
            if (user != null) {
                logBO.setEmail(user.getEmail());
                logBO.setLoginId(user.getLoginId());
            } else {
                logBO.setEmail(req.getParameter("email"));
            }
            String json = JSONObject.toJSONString(mapParam);
            logBO.setParamsJson(json);
            logBO.setSrcIp(map.get("hostIp").toString());
            logBO.setServerIp(super.getIpAddr((HttpServletRequest) req));
            if (request.getType().getTypeStr().equals("post")) {
                userOptLogService.insertUserOptLog(logBO);
            }

        }
    }

    private AccessRequest assemblyAccessReq(ServletRequest req) {
        return new AccessRequest(withOutContextPath(req), getMethodType(req), transHttpReq(req).getSession());
    }

    private String getCurrUrl(ServletRequest req) {
        return transHttpReq(req).getRequestURI().trim();
    }

    private String removeContextPath(String url) {
        if (url.equals(contextPath)) {
            return "/";
        }
        return url.split(contextPath)[1].trim();
    }

    private String withOutContextPath(ServletRequest req) {
        String urlWithContextPath = getCurrUrl(req);
        return removeContextPath(urlWithContextPath);
    }

    private UrlMethodType getMethodType(ServletRequest req) {

        String method = transHttpReq(req).getMethod().trim();
        return UrlMethodType.getUrlMethodType(method);
    }

    private HttpServletRequest transHttpReq(ServletRequest req) {
        return (HttpServletRequest) req;
    }

    private void responseJson(HttpServletResponse response, Object responseObject) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append(JSON.toJSONString(responseObject));
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    @Override
    public void destroy() {

    }
}
